import { logSpecial } from "@/app/api/util/io/log";
import { AnyFn } from "@/types";
import { UnionToIntersection } from "@reduxjs/toolkit/dist/tsHelpers";
import dayjs from "dayjs";
export * from '../../app/(dashboard)/common/util'//在这里导出前端专用工具函数

//下面的是前后端通用的工具函数

/**使用JSON做深拷贝 */
export function deep_JSON<T>(data: T): T {
    return JSON.parse(JSON.stringify(data))
}
/**睡眠。搭配await
 * @param time 要等待的时间，单位ms，默认1000
 */
export function sleep(time: number = 1000) {
    return new Promise((resolve) => setTimeout(resolve, time))
}

type Obj = Record<any, any>
/**合并对象。 基于Object.assign。
 * @param mainObj 主对象。不能为空
 * @param otherObj 要被合并到主对象上的对象
 * @returns 返回一个新对象，避免修改原始对象
 */
export const mergeObj = <T extends Obj, D extends Obj[]>(mainObj: T, ...otherObj: D): T & UnionToIntersection<D[number]> => {
    return Object.assign({}, mainObj, ...otherObj)
}
/**把时间转为 YYYY-MM-DD HH:mm:ss
 * @param date 要传递给dayjs的参数，不传递则使用当前时间
 * @returns 字符串
 */
export const formatDay = (date?: dayjs.ConfigType) => {
    return dayjs(date).format('YYYY-MM-DD HH:mm:ss')
}
/**获得日期 YYYY-MM-DD 
 * @param date 要传递给dayjs的参数，不传递则使用当前时间
 * @returns 字符串
 */
export const getToday = (date?: dayjs.ConfigType) => {
    return dayjs(date).format('YYYY-MM-DD')
}

/**获得两个日期之间的所有日期数组（包含这两天）  
 * @param start 开始日期
 * @param end 结束日期
 * @returns 日期字符串数组 YYYY-MM-DD 格式
 * @example
 * const startDate = '2023-10-09T13:14:15';
 * const endDate = '2023-10-13T23:14:15';
 * const datesBetween = getDatesBetween(startDate, endDate);
 * console.log(datesBetween);//['2023-10-09', '2023-10-10', '2023-10-11', '2023-10-12', '2023-10-13']
 */
export function getDatesBetween(start: dayjs.ConfigType, end: dayjs.ConfigType) {
    const startDate = dayjs(start).startOf('day');
    const endDate = dayjs(end).startOf('day');
    const dates: string[] = [];
    let currentDate = startDate;
    while (currentDate.isBefore(endDate) || currentDate.isSame(endDate)) {
        dates.push(currentDate.format('YYYY-MM-DD'));
        currentDate = currentDate.add(1, 'day');
    }
    return dates;
}


/**防抖。主要思想是，短时间内触发的多个函数，只执行最后一次(等待指定时间后执行)。会刷新等待时间。  （搜索框联想）
 * @param func 要防抖的函数。调用return的函数时传参，可以在这里接收到
 * @param time 防抖的时间，毫秒
 * @returns 返回一个函数，可以用来绑定事件。调用时可以给这个函数传参
 */
export const debounce = (func: AnyFn, time: number): AnyFn => {
    let timer: NodeJS.Timeout
    return function (this: any, ...argu) {
        const context = this;
        clearTimeout(timer)
        timer = setTimeout(() => {
            func.apply(context, argu) //通过剩余参数的形式传递
        }, time);
    }
}
/**节流。思想是一段时间内多次触发，只执行一次  （按很多下平a只触发一次）
* @param func 要触发的函数。调用return的函数时传的参，可以在这里接收到
* @param time 时间间隔。毫秒
* @returns 返回一个函数，可以用于绑定事件。调用时可以给这个函数传参
*/
export const throttle = (func: AnyFn, time: number): AnyFn => {
    /**节流阀 */
    let flag = false
    return function (this: any, ...argu) {
        if (flag) return
        const context = this;
        flag = true
        func.apply(context, argu) //通过剩余参数的形式传递
        setTimeout(() => {//指定时间间隔后关闭节流阀
            flag = false
        }, time);
    }
}
/**判断是否为空对象 */
export function isEmptyObject(obj: Obj) {
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            return false;
        }
    }
    return true;
}
/**如果url不是HTTPS开头的，就改为HTTPS开头 */
export function httpToHttps(url: string) {
    if (!url.startsWith("https")) {
        return url.replace("http", "https");
    }
    return url
}
/**数组随机排序。会改变原数组 */
export function randomSort<T>(arr: T[]) {
    // Fisher-Yates 算法随机排序数组
    for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    return arr
}
/**数组去重 （不适合对象数组） */
export function uniqueArray<T extends string | number | boolean>(arr: T[]): T[] {
    return [...new Set(arr)];
}
/**数字保留n位小数，并且仍然是浮点数
 * @param num 数字
 * @param n 保留几位，默认2 最常用
 * @returns 浮点数
 */
export function toFixAndFloat(num: number, n: number = 2) {
    return parseFloat(num.toFixed(n))
}

/**根据枚举类型，创建一个特定格式的对象
 * @param enumObj 枚举。 以枚举的键构造，所以 枚举的值和键最好相等，避免非预期结果
 * @param initVal 初始化的值，比如空数组，空对象
 * @returns 返回一个对象，构造见示例 
 * @example 
 * enum yygiftActions {
 *   text_create = 'text_create',
 *   img_view = 'img_view',
 *   img_download = 'img_download'
 * }
 * const res = generateObjectFromEnum(yygiftActions, [])
 * res --> {
 *   text_create: [],
 *   img_view: [],
 *   img_download: []
 * }
 */
export function generateObjectFromEnum<T extends string, D>(enumObj: Record<T, string>, initVal: D): { [key in keyof typeof enumObj]: D } {
    return Object.entries(enumObj).reduce((obj, [key, value]) => {
        obj[key as keyof typeof enumObj] = Array.isArray(initVal) ? [] : {} as any;
        return obj;
    }, {} as { [key in keyof typeof enumObj]: typeof initVal });
}


/**获得文件名的后缀，包含 .  */
export function getSuffix(name: string) {
    return name.substring(name.lastIndexOf("."))
}
/**传入泛型就有类型提示的 JSON.parse  */
export const jsonParse = <T>(json: string): T => {
    return JSON.parse(json) as T
}
